﻿#nullable enable

using System;
using System.Collections.Generic;
using Volo.Abp.Domain.Services;

namespace PHMEE.EnergyEfficiency;

public class CIIService : DomainService
{
    public CIIService()
    {

    }
    
    /// <summary>
    /// 公式 6.1：CII基线
    /// </summary>
    /// <param name="vesselType"></param>
    /// <param name="dwt"></param>
    /// <param name="gt"></param>
    /// <returns></returns>
    private static float CIIRef(VesselType vesselType, float dwt, float gt)
    {
        var ciiBaselineParameters = VesselTypeHelper.GetCIIBaselineParameters(vesselType, dwt, gt);

        return (float)(ciiBaselineParameters.A * Math.Pow(ciiBaselineParameters.Capacity, -ciiBaselineParameters.C));
    }

    /// <summary>
    /// 公式 6.2：要求的年度营运CII
    /// </summary>
    /// <param name="vesselType"></param>
    /// <param name="dwt"></param>
    /// <param name="gt"></param>
    /// <param name="vesselAnnualConfigZ">折减系数 Z</param>
    /// <returns></returns>
    public static float RequiredCII(VesselType vesselType,
        float dwt, float gt,
        float vesselAnnualConfigZ)
    {
        var ciiRef = CIIRef(vesselType, dwt, gt);

        return (1 - vesselAnnualConfigZ / 100.0F) * ciiRef;
    }

    /// <summary>
    /// 获取 cii 的评级 TODO: 如果抛出异常，改为返回 null
    /// </summary>
    /// <param name="cii"></param>
    /// <param name="vesselType"></param>
    /// <param name="dwt"></param>
    /// <param name="gt"></param>
    /// <param name="vesselAnnualConfigZ">折减系数 Z</param>
    /// <returns></returns>
    public static CIIGrade DetermineCIIGrade(float cii, VesselType vesselType, float dwt, float gt,
        float vesselAnnualConfigZ)
    {
        var requiredCII = RequiredCII(vesselType, dwt, gt, vesselAnnualConfigZ);
        var boundaries = GetAllGradeBoundaries(requiredCII, vesselType, dwt);

        if (cii <= boundaries[CIIGrade.A])
        {
            return CIIGrade.A;
        }

        if (cii <= boundaries[CIIGrade.B])
        {
            return CIIGrade.B;
        }

        if (cii <= boundaries[CIIGrade.C])
        {
            return CIIGrade.C;
        }

        if (cii <= boundaries[CIIGrade.D])
        {
            return CIIGrade.D;
        }

        return CIIGrade.E; // 如果CII值高于所有边界，则为最低等级
    }

    /// <summary>
    /// 公式 6.2 的子公式，计算 CII 边界值
    /// </summary>
    /// <param name="requiredCII"></param>
    /// <param name="targetCIIGrade"></param>
    /// <param name="vesselType"></param>
    /// <param name="dwt"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentException"></exception>
    public static float GetCIIGradeBoundary(float requiredCII, CIIGrade targetCIIGrade, VesselType vesselType,
        float dwt)
    {
        var allBoundaries = GetAllGradeBoundaries(requiredCII, vesselType, dwt);

        if (allBoundaries.TryGetValue(targetCIIGrade, out float boundary))
        {
            return boundary;
        }

        // TODO: 处理异常
        throw new ArgumentException("Target CIIGrade is not valid.");
    }

    /// <summary>
    /// 获取 CII 等级边界值
    /// </summary>
    /// <param name="requiredCII"></param>
    /// <param name="vesselType"></param>
    /// <param name="dwt"></param>
    /// <returns></returns>
    public static IDictionary<CIIGrade, float> GetAllGradeBoundaries(float requiredCII, VesselType vesselType,
        float dwt)
    {
        var boundaries = new Dictionary<CIIGrade, float>(4);
        var ddVector = VesselTypeHelper.GetDdVector(vesselType, dwt);

        boundaries[CIIGrade.A] = ddVector.D1 * requiredCII;
        boundaries[CIIGrade.B] = ddVector.D2 * requiredCII;
        boundaries[CIIGrade.C] = ddVector.D3 * requiredCII;
        boundaries[CIIGrade.D] = ddVector.D4 * requiredCII;

        return boundaries;
    }
}